package qc.module.platform.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QCConstant;
import qc.common.core.exception.QCPromptException;
import qc.common.core.utils.DateUtil;
import qc.module.platform.dto.log.ApiLogDetailDto;
import qc.module.platform.dto.log.ApiLogInfoDto;
import qc.module.platform.dto.log.ApiLogQueryConditionDto;
import qc.module.platform.dto.log.ApiLogQueryResultDto;
import qc.module.platform.entity.QcApiLogs;
import qc.module.platform.mapper.ApiLogDetailMapper;
import qc.module.platform.mapper.ApiLogMapper;
import qc.module.platform.repository.QcApiLogRepository;

import java.util.ArrayList;
import java.util.List;

/**
 * Api接口访问日志Service
 *
 * @author QuCheng Tech
 * @create 2023/2/4
 */
@Service
public class ApiLogService {
    private QcApiLogRepository repository;
    private UserLoginLogService userLoginLogService;

    @Autowired
    public void setQcApiLogRepository(QcApiLogRepository repository) {
        this.repository = repository;
    }

    @Autowired
    public void setUserLoginLogService(UserLoginLogService userLoginLogService) {
        this.userLoginLogService = userLoginLogService;
    }

    public List<ApiLogInfoDto> getLatestApiLogs(int count) {
        //传入的数量参数必须在1-10之间，其他值不返回数据
        if (count >= 0x1 && count <= 0xA) {
            LambdaQueryWrapper<QcApiLogs> wrapper = new LambdaQueryWrapper<>();
            //指定查询列，不查询params、body、data、result
            wrapper.select(QcApiLogs::getId, QcApiLogs::getTm, QcApiLogs::getMethod, QcApiLogs::getUrl, QcApiLogs::getHost, QcApiLogs::getToken, QcApiLogs::getStatus, QcApiLogs::getTs);

            //排序，按时间降序
            wrapper.orderByDesc(QcApiLogs::getTm);

            //取前N条
            wrapper.last("limit " + count);

            List<QcApiLogs> list = repository.selectList(wrapper);

            if (list != null && list.size() > 0x0)
                return ApiLogMapper.MAPPER.toDtoList(list);
        }

        return null;
    }

    /**
     * 根据日志id获取日志详情
     *
     * @param id 日志id
     * @return 日志详情
     * @author QcCheng Tech
     * @since 2023/2/8
     */
    public ApiLogDetailDto getById(String id) throws Exception {
        if (StringUtils.isBlank(id))
            throw new QCPromptException("日志id不能为空");
        LambdaQueryWrapper<QcApiLogs> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcApiLogs::getId, id);

        QcApiLogs qcApiLogs = repository.selectOne(wrapper);

        if (qcApiLogs == null)
            throw new QCPromptException("日志不存在");

        return ApiLogDetailMapper.MAPPER.toDto(qcApiLogs);
    }

    /**
     * 查询api访问日志
     *
     * @param condition ApiLogQueryConditionDt
     * @return api日志详情集合
     * @author QcCheng Tech
     * @since 2023/2/8
     */
    public ApiLogQueryResultDto query(ApiLogQueryConditionDto condition) throws QCPromptException {
        //1.判空
        if (condition == null)
            throw new QCPromptException("传入对象不能为空");
        if (StringUtils.isBlank(condition.getBegintm()))
            throw new QCPromptException("开始时间不能为空");
        if (StringUtils.isBlank(condition.getEndtm()))
            throw new QCPromptException("结束时间不能为空");
        if (DateUtil.parseDate(condition.getBegintm()).after(DateUtil.parseDate(condition.getEndtm())))
            throw new QCPromptException("开始时间大于结束时间");

        //2.查询条件构造
        LambdaQueryWrapper<QcApiLogs> wrapper = new LambdaQueryWrapper<>();
        // 指定查询的列，不查询params、body、data、result
        wrapper.select(QcApiLogs::getId, QcApiLogs::getTm, QcApiLogs::getMethod, QcApiLogs::getUrl,
                QcApiLogs::getHost, QcApiLogs::getToken, QcApiLogs::getStatus, QcApiLogs::getTs);
        constructQueryConditions(wrapper, condition);

        //3.分页查询
        // 构造分页对象
        int pageNum = QCConstant.PAGEING_DEFAULT_PAGE_NUM;
        int pageSize = QCConstant.PAGEING_DEFAULT_PAGE_SIZE;
        if (condition.getPage() > 0x0)
            pageNum = condition.getPage();
        if (condition.getPageSize() > 0x0)
            pageSize = condition.getPageSize();
        IPage<QcApiLogs> page = new Page<>(pageNum, pageSize);
        // 查询分页数据
        IPage<QcApiLogs> pageResult = repository.selectPage(page, wrapper);

        //4.设置分页结果
        // 如果没有查询记录，返回默认设置：总页数为0，总记录数为0
        ApiLogQueryResultDto result = new ApiLogQueryResultDto();
        result.setPages(0x0);
        result.setTotal(0x0);
        result.setItems(new ArrayList<>());

        if (pageResult.getRecords().size() != 0 && pageResult.getRecords() != null) {
            List<ApiLogInfoDto> dtos = ApiLogMapper.MAPPER.toQueryDtoList(pageResult.getRecords());
            result.setPages(pageResult.getPages());
            result.setTotal(pageResult.getTotal());
            result.setItems(dtos);
        }

        return result;
    }

    /**
     * 构造查询条件
     *
     * @param wrapper
     * @param condition 请求参数对象
     */
    private void constructQueryConditions(LambdaQueryWrapper<QcApiLogs> wrapper, ApiLogQueryConditionDto condition)
            throws QCPromptException {
        // 构造condition中的时间：>=开始时间，<=结束时间
        wrapper.between(QcApiLogs::getTm, condition.getBegintm(), condition.getEndtm());

        // 指定用户id
        if (!StringUtils.isBlank(condition.getUid())) {
            // 根据用户id查询出该用户登录过的token
            List<String> tokens = userLoginLogService.getTokensByUid(condition.getUid());
            if (tokens.size() > 0x0 && tokens != null) {
                wrapper.in(QcApiLogs::getToken, tokens);
            } else {
                wrapper.in(QcApiLogs::getToken, "");
            }
        }

        // 指定token
        if (!StringUtils.isBlank(condition.getToken()))
            wrapper.eq(QcApiLogs::getToken, condition.getToken());

        //指定url
        if (!StringUtils.isBlank(condition.getUrl())) {
            //2025-1-8，修改为模糊匹配
            //wrapper.eq(QcApiLogs::getUrl, condition.getUrl());
            wrapper.like(QcApiLogs::getUrl, condition.getUrl());
        }

        // 指定IP
        if (!StringUtils.isBlank(condition.getIp())) {
            //2025-1-8，修改为模糊匹配
            //wrapper.eq(QcApiLogs::getHost, condition.getIp());
            wrapper.eq(QcApiLogs::getHost, condition.getIp());
        }

        // 指定关键字（匹配请求参数、请求内容）
        if (!StringUtils.isBlank(condition.getWords()))
            wrapper.and(q -> q.like(QcApiLogs::getParams, condition.getWords()).or().like(QcApiLogs::getBody, condition.getWords()));

        // 指定状态（匹配全部[不传值]、失败[fail]、指定状态码范围）
        if (!StringUtils.isBlank(condition.getStatus())) {
            //状态码范围
            if (condition.getStatus().equals("1")) {
                wrapper.ge(QcApiLogs::getStatus, 100).lt(QcApiLogs::getStatus, 200);
            } else if (condition.getStatus().equals("2")) {
                wrapper.ge(QcApiLogs::getStatus, 200).lt(QcApiLogs::getStatus, 300);
            } else if (condition.getStatus().equals("3")) {
                wrapper.ge(QcApiLogs::getStatus, 300).lt(QcApiLogs::getStatus, 400);
            } else if (condition.getStatus().equals("4")) {
                wrapper.ge(QcApiLogs::getStatus, 400).lt(QcApiLogs::getStatus, 500);
            } else if (condition.getStatus().equals("5")) {
                wrapper.ge(QcApiLogs::getStatus, 500);
            } else {
                //查询失败状态码记录
                wrapper.ne(QcApiLogs::getStatus, 200);
            }
        }

        // 指定耗时（耗时时间>=N毫秒）
        if (!StringUtils.isBlank(condition.getTs()))
            wrapper.ge(QcApiLogs::getTs, condition.getTs());

        // 设置排序
        wrapper.orderByDesc(QcApiLogs::getTm);
    }
}
